package main;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PerformanceAnalysis {

	final static String topicTtermsMatchedFileName = "data/topic-terms-matched-07.txt";

	final static String submittedResultListFileName = "data/submitted-result-list-07.txt";

	final static String goldStandardFileName = "data/gold-standard-07.txt";

	final static String outputFileName1 = "data/output1-gold-standard-07.txt";

	final static String outputFileName2 = "data/output2-gold-standard-07.txt";

	String topPassages;

	String[] phases;

	int outputLine = 1000;

	String outputFile;

	List goldStandard = new ArrayList<Topic>();

	List submittedResultList = new ArrayList<Topic>();

	List topicTtermsMatchedList = new ArrayList<Topic>();

	List outputList = new ArrayList<Topic>();

	final static int totalSize = 1000;

	/*
	 * 1. Read input files. gold-standard-07.txt (goldTopicID, goldDocID,
	 * goldOthers), submitted-result-list-07.txt (topicID, docID, others),
	 * topic-terms-matched-07.txt (termTopicID, termDocID, termOthers). 
	 * 2. Comparison
	 * for (goldTopicID and goldDocID in gold-standard-07.txt)
	 * for (topicID and docID in submitted-result-list-07.txt)
	 * if topicID = goldTopicID
	 * if docID = goldDocID
	 * newTopicID = topicID
	 * newDocID = docID
	 * newOthers = others
	 * print NewList (newTopicID, newDocID, newOthers)
	 * else if
	 * continue
	 * 3. Print information in topic-terms-matched-07.txt.
	 * for (newTopicID and newDocID in NewList)
	 * for (termTopicID and termDocID in topic-terms-matched-07.txt)
	 * if newTopicID = termTopicID
	 * if newDocID = termDocID
	 * newTermTopicID = termTopicID
	 * newTermDocID = termDocID
	 * newTermOthers = termOthers
	 * print NewPsgList (newTermTopicID, newTermDocID, newTermOthers)
	 * else if
	 * continue
	 */
	public PerformanceAnalysis() {

		// initConfig();

		read();
		System.out.println("sort begin.............");
		Date begin = new Date();
		for (Iterator iter = goldStandard.iterator(); iter.hasNext();) {
			Topic topic = (Topic) iter.next();
			Topic topicSubmittedResult = getTopic(topic.getId(),submittedResultList);
			Topic topicTtermsMatched = getTopic(topic.getId(),topicTtermsMatchedList);
			selectTopicTtermsMatched(topic,topicSubmittedResult,topicTtermsMatched);
//			topics3.add(combine(topic, topic1, topic2));
		}

		System.out.println("sort end.............");
		Date end = new Date();
		write(topicTtermsMatchedList);
		System.out.println("sort time:" + (end.getTime() - begin.getTime()));

	}

	private void selectTopicTtermsMatched(Topic topicGoldStandard,Topic topicSubmittedResult,Topic topicTtermsMatched){
		List psgsGoldStandard = topicGoldStandard.getPassages();
		List psgsSubmittedResult = topicSubmittedResult.getPassages();
		List psgsTtermsMatched = topicTtermsMatched.getPassages();
		for(int i = 0; i<psgsGoldStandard.size();i++){
			Passage p1 = (Passage) psgsGoldStandard.get(i);
			for(int j = 0;j<psgsSubmittedResult.size();j++){
				Passage p2 = (Passage) psgsSubmittedResult.get(j);
//				if(p1.getTopicID().equals(p2.getTopicID())&&p1.getDocumentID().equals(p2.getDocumentID())){
				if(isCross(p1, p2)){
					Passage psg = (Passage)psgsTtermsMatched.get(j);
					psg.setOutString(p2.getOutString());
					topicTtermsMatched.addSortedPassage(psg);
					break;
				}
			}
		}
	}
	
	private boolean isCross(Passage p1,Passage p2){
		if(p1.getTopicID().equals(p2.getTopicID())&&p1.getDocumentID().equals(p2.getDocumentID())){
			//p2 contains p1.
			if (p1.getStart() >= p2.getStart() && (p1.getStart() + p1.getOffset()) <= (p2.getStart() + p2.getOffset())) {
				return true;
			}
			// p1 contains p2.
			else if (p1.getStart() <= p2.getStart() && ((p1.getStart() + p1.getOffset()) >= (p2.getStart() + p2.getOffset()))) {
				return true;
			} 
			// p1 and p2 have overlapping, and p1 is in front of p2.
			else if (p1.getStart() <= p2.getStart() && p2.getStart() <= (p1.getStart() + p1.getOffset()) && ((p1.getStart() + p1.getOffset()) <= (p2.getStart() + p2.getOffset()))) {
				return true;
			} 
			// p1 and p2 have overlapping, and p2 is in front of p1.
			else if (p2.getStart() <= p1.getStart() && p1.getStart() <= (p2.getStart() + p2.getOffset()) && ((p2.getStart() + p2.getOffset()) <= (p1.getStart() + p1.getOffset()))) {
				return true;
			}
		}
		return false;
	}
	
	
	private void filtSamePassage(List psgs) {

		List removeIndex = new ArrayList();
		for (int i = 1; i < psgs.size(); i++) {
			Passage psg1 = (Passage) psgs.get(0);
			Passage psg2 = (Passage) psgs.get(i);

			if (psg1.getDocumentID().equals(psg2.getDocumentID())) {
				removeIndex.add(new Integer(i));
			}
		}
		// remove psgs
		if (removeIndex.size() > 0) {
			for (int i = psgs.size(); i >= 0; i--) {
				for (int j = 0; j < removeIndex.size(); j++) {
					if (i == ((Integer) removeIndex.get(j)).intValue()) {
						psgs.remove(i);
					}
				}
			}
			filtSamePassage(psgs);
		}
	}

	private void write(List topics) {
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFileName1));
			for (Iterator iter = topics.iterator(); iter.hasNext();) {
				Topic topic = (Topic) iter.next();
				int i = 0;
				for (Iterator itP = topic.getSortedPassages().iterator(); itP.hasNext() && i < outputLine; i++) {
					Passage psg = (Passage) itP.next();
					bw.write(psg.getTopicID()+ " " + psg.getPassageContent() + "\r\n");
					System.out.println(psg);
				}
			}
			bw.close();
			BufferedWriter bw2 = new BufferedWriter(new FileWriter(outputFileName2));
			for (Iterator iter = topics.iterator(); iter.hasNext();) {
				Topic topic = (Topic) iter.next();
				int i = 0;
				for (Iterator itP = topic.getSortedPassages().iterator(); itP.hasNext() && i < outputLine; i++) {
					Passage psg = (Passage) itP.next();
					bw2.write(psg.getTopicID()+ " " + psg.getOutString() + "\r\n");
					System.out.println(psg);
				}
			}
			bw2.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private Topic combine(Topic topic1, Topic topic2, Topic topic3) {
		List<Passage> psgs1 = topic1.getPassages();
		List<Passage> psgs2 = topic2.getPassages();
		List<Passage> psgs3 = topic3.getPassages();
		Topic topic = new Topic();
		// for (Iterator<Passage> iter1 = psgs1.iterator(); iter1.hasNext();) {
		// Passage psg1 = iter1.next();
		// for (Iterator<Passage> iter2 = psgs2.iterator(); iter2.hasNext();) {
		// Passage psg2 = iter2.next();
		// if (psg1.getDocumentID().equals(psg2.getDocumentID())) {
		// topic3.addPassage(merge(psg1, psg2));
		// iter1.remove();
		// iter2.remove();
		// break;
		// }
		// }
		// }
		topic.getPassages().addAll(psgs1);
		topic.getPassages().addAll(psgs2);
		topic.getPassages().addAll(psgs3);
		Collections.sort(topic.getPassages(), new PassageComp());
		// filtSamePassage(topic3.getSortedPassages());
		topic.setSortedPassages(topic.getPassages().subList(0, 1000));
		// filtSamePassage(topic3.getSortedPassages());
		return topic;
	}

	// This method is to merge the passages with same documentIDs.
	// There are two main types of conditions between two passages. One is that
	// they are independent; the other is they are intercross each other.
	private Passage merge(Passage psg1, Passage psg2) {
		Passage psg = new Passage();
		if (psg1.getStart() >= psg2.getStart() && (psg1.getStart() + psg1.getOffset()) <= (psg2.getStart() + psg2.getOffset())) {
			psg.setDocumentID(psg2.getDocumentID());
			psg.setStart(psg2.getStart());
			psg.setOffset(psg2.getOffset());
			psg.setWeight(psg1.getWeight().add(psg2.getWeight()));
		} else if (psg1.getStart() <= psg2.getStart() && ((psg1.getStart() + psg1.getOffset()) >= (psg2.getStart() + psg2.getOffset()))) {
			psg.setDocumentID(psg1.getDocumentID());
			psg.setStart(psg1.getStart());
			psg.setOffset(psg1.getOffset());
			psg.setWeight(psg1.getWeight().add(psg2.getWeight()).divide(new BigDecimal(2)));
			// psg.setWeight(psg1.getWeight().add(psg2.getWeight()).divide(new
			// BigDecimal(2)));
		} else if (psg2.getStart() <= (psg1.getStart() + psg1.getOffset()) && ((psg1.getStart() + psg1.getOffset()) <= (psg2.getStart() + psg2.getOffset()))) {
			psg.setDocumentID(psg1.getDocumentID());
			psg.setStart(psg1.getStart());
			psg.setOffset(psg2.getStart() + psg2.getOffset() - psg1.getStart());
			psg.setWeight(psg1.getWeight().add(psg2.getWeight()).divide(new BigDecimal(2)));
		} else if (psg1.getStart() <= (psg2.getStart() + psg2.getOffset()) && ((psg2.getStart() + psg2.getOffset()) <= (psg1.getStart() + psg1.getOffset()))) {
			psg.setDocumentID(psg1.getDocumentID());
			psg.setStart(psg2.getStart());
			psg.setOffset(psg1.getStart() + psg1.getOffset() - psg2.getStart());
			psg.setWeight(psg1.getWeight().add(psg2.getWeight()).divide(new BigDecimal(2)));
		} else if ((psg1.getStart() + psg1.getOffset()) < psg2.getStart() || ((psg2.getStart() + psg2.getOffset()) < psg1.getStart())) {
			if (psg1.getWeight().compareTo(psg2.getWeight()) < 0) {
				psg.setDocumentID(psg2.getDocumentID());
				psg.setStart(psg2.getStart());
				psg.setOffset(psg2.getOffset());
				psg.setWeight(psg2.getWeight());
			} else {
				psg.setDocumentID(psg1.getDocumentID());
				psg.setStart(psg1.getStart());
				psg.setOffset(psg1.getOffset());
				psg.setWeight(psg1.getWeight());
			}
		} else {
			psg.setDocumentID(psg1.getDocumentID());
			psg.setStart(psg1.getStart());
			psg.setOffset(psg1.getOffset());
			psg.setWeight(psg1.getWeight());
		}
		psg.setTerms(psg1.getTerms());
		psg.setTopicID(psg1.getTopicID());
		return psg;
	}

	/*
	 * private List[] split(List psgs) { List[] lists = new List[phases.length];
	 * for (int i = 0; i < phases.length; i++) { if(i==0){ lists[i] = new
	 * ArrayList(); lists[i].addAll(psgs.subList(0 ,
	 * Integer.valueOf(phases[i]).intValue())); }else{ lists[i] = new
	 * ArrayList(); lists[i].addAll(psgs.subList(Integer.valueOf(phases[i -
	 * 1]).intValue(), Integer.valueOf(phases[i]).intValue())); } } return
	 * lists; }
	 * 
	 * private List merge(List[] lists) { List list = new ArrayList(); for (int
	 * i = 0; i < lists.length; i++) { list.addAll(lists[i]); } return list; }
	 * 
	 * private List cluster(List psgs, List clusters) { Passage firstPsg =
	 * (Passage) psgs.get(0); List clusterX = new ArrayList(); for (Iterator itp =
	 * psgs.iterator(); itp.hasNext();) { Passage psg = (Passage) itp.next();
	 * BigDecimal simRank = calSimRank(firstPsg, psg);
	 * psg.setSimilarityRank(simRank); if (simRank.intValue() == 1) {
	 * clusterX.add(psg); // itp.remove(); } } clusters.add(clusterX);
	 * psgs.removeAll(clusterX); if (psgs.size() > 0) { cluster(psgs, clusters); }
	 * return clusters; }
	 * 
	 * private List resort(List clusters) { int clusterSize = 0; int clusterNum =
	 * clusters.size(); for (int i = 0; i < clusterNum; i++) { List clusterX =
	 * (List) clusters.get(i); if (clusterX.size() > clusterSize) { clusterSize =
	 * clusterX.size(); } }
	 * 
	 * List newlist = new ArrayList(); // init list for (int i = 0; i <
	 * clusterSize * clusterNum; i++) { newlist.add(null); }
	 *  // set psg to new list for (int i = 0; i < clusterNum; i++) { List
	 * clusterX = (List) clusters.get(i); for (int j = 0; j < clusterX.size();
	 * j++) { newlist.set(clusterNum * j + i, clusterX.get(j)); } }
	 *  // remove null for (int i = newlist.size() - 1; i >= 0; i--) { if
	 * (newlist.get(i) == null) { newlist.remove(i); } }
	 * 
	 * return newlist; }
	 * 
	 * private void filtSamePassage(List psgs) {
	 * 
	 * List removeIndex = new ArrayList(); for (int i = 1; i < psgs.size(); i++) {
	 * Passage psg1 = (Passage) psgs.get(0); Passage psg2 = (Passage)
	 * psgs.get(i);
	 * 
	 * if (psg1.getDocumentID().equals(psg2.getDocumentID())) {
	 * removeIndex.add(new Integer(i)); } } // remove psgs if
	 * (removeIndex.size() > 0) { for (int i = psgs.size(); i >= 0; i--) { for
	 * (int j = 0; j < removeIndex.size(); j++) { if (i == ((Integer)
	 * removeIndex.get(j)).intValue()) { psgs.remove(i); } } }
	 * filtSamePassage(psgs); } }
	 * 
	 *//**
		 * @param firstPsg
		 * @param psg
		 * @return
		 */
	/*
	 * private BigDecimal calSimRank(Passage firstPsg, Passage psg) { String[]
	 * firstTerms = firstPsg.getFoundTerms(); String[] theTerms =
	 * psg.getFoundTerms(); int totalNum = firstTerms.length; if
	 * (theTerms.length > firstTerms.length) { totalNum = theTerms.length; } int
	 * sameNum = 0; for (int i = 0; i < firstTerms.length; i++) { for (int j =
	 * 0; j < theTerms.length; j++) { if (firstTerms[i].equals(theTerms[j])) {
	 * sameNum++; } } } BigDecimal simRank = new BigDecimal(sameNum).divide(new
	 * BigDecimal(totalNum), 4, BigDecimal.ROUND_HALF_EVEN); return simRank; }
	 */

	// Read the files.
	// The files are really read by the methods of
	private void read() {
		System.out.println("read file begin.............");
		try {

			// readPassages();
			readGoldStandard();

			readSubmittedResultList();

			readTopicTtermsMatched();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("read file end.............");

	}

	/**
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void readGoldStandard() throws FileNotFoundException, IOException {
		BufferedReader fmt_file = new BufferedReader(new FileReader(goldStandardFileName));
		for (String tmp = fmt_file.readLine(); tmp != null; tmp = fmt_file.readLine()) {
			String[] tmpArr = tmp.split("	");
			if (tmpArr.length >= 5) {
				Topic topic = getTopic(tmpArr[0],goldStandard);
				if (topic == null) {
					topic = new Topic();
					topic.setId(tmpArr[0]);
					goldStandard.add(topic);
				}

				Passage psg = new Passage();
				psg.setTopicID(tmpArr[0]);
				psg.setDocumentID(tmpArr[1]);
//				psg.setPassageID(tmpArr[2]);
//				psg.setWeight(new BigDecimal(tmpArr[3]));
				psg.setStart(new Integer(tmpArr[2]));
				psg.setOffset(new Integer(tmpArr[3]));
//				psg.setTerms(tmpArr[6]);
				psg.setOutString(tmp);
				topic.addPassage(psg);
			} else {
				System.err.println("file format error!");
			}
		}
		fmt_file.close();
	}

	private void readSubmittedResultList() throws FileNotFoundException, IOException {
		BufferedReader fmt_file = new BufferedReader(new FileReader(submittedResultListFileName));
		for (String tmp = fmt_file.readLine(); tmp != null; tmp = fmt_file.readLine()) {
			String[] tmpArr = tmp.split(" ");
			if (tmpArr.length == 7) {
				Topic topic = getTopic(tmpArr[0], submittedResultList);
				if (topic == null) {
					topic = new Topic();
					topic.setId(tmpArr[0]);
					submittedResultList.add(topic);
				}

				Passage psg = new Passage();
				psg.setTopicID(tmpArr[0]);
				psg.setDocumentID(tmpArr[1]);
				psg.setPassageID(tmpArr[2]);
				psg.setWeight(new BigDecimal(tmpArr[3]));
				psg.setStart(new Integer(tmpArr[4]));
				psg.setOffset(new Integer(tmpArr[5]));
				psg.setTerms(tmpArr[6]);
				psg.setOutString(tmp);
				topic.addPassage(psg);
			} else {
				System.err.println("file format error!");
			}
		}
		fmt_file.close();
	}

	private void readTopicTtermsMatched() throws FileNotFoundException, IOException {
		BufferedReader top_file = new BufferedReader(new FileReader(topicTtermsMatchedFileName));
		String topicid = "";
		for (String tmp = top_file.readLine(); tmp != null; tmp = top_file.readLine()) {
			if (tmp.startsWith("Topic#")) {
				Topic topic = new Topic();
				topic.setId(tmp.replaceFirst("Topic#", ""));
				topicid = topic.getId();
				topicTtermsMatchedList.add(topic);
			} else if (tmp.startsWith("passage")) {
				Topic topic = getTopic(topicid, topicTtermsMatchedList);
				Passage psg = new Passage();
				psg.setTopicID(topicid);
				psg.setPassageContent(tmp);
//				Pattern p = Pattern.compile("passage .* terms was found >> ");
//				Matcher m = p.matcher(tmp);
//				StringBuffer sb = new StringBuffer();
//				if (m.find()) {
//					m.appendReplacement(sb, "");
//					m.appendTail(sb);
//				} else {
//					Pattern p2 = Pattern.compile("passage .* terms was found\\.");
//					Matcher m2 = p2.matcher(tmp);
//					if (m2.find()) {
//						sb = new StringBuffer();
//					}
//				}
//				psg.setTerms(sb.toString());
//				psg.setFoundTerms(sb.toString().split(" "));
				topic.addPassage(psg);
			}
		}
		top_file.close();
	}

	/**
	 * @param id
	 * @return
	 */
	private Topic getTopic(String id, List topics) {
		for (Iterator iter = topics.iterator(); iter.hasNext();) {
			Topic thetopic = (Topic) iter.next();
			if (id.equals(thetopic.getId())) {
				return thetopic;
			}
		}
		return null;
	}


	class PassageComp implements Comparator<Passage> {

		public int compare(Passage o1, Passage o2) {
			return o2.getWeight().compareTo(o1.getWeight());
		}

	}

	public static void main(String[] args) {
		PerformanceAnalysis ac = new PerformanceAnalysis();

	}
}
